﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;

namespace SwaggerExtensions
{
    public class SwaggerOptionalFormDataFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor descriptor)
            {
                // If not [AllowAnonymous] and [Authorize] on either the endpoint or the controller...
                if (!context.ApiDescription.CustomAttributes().Any((a) => a is AllowAnonymousAttribute)
                    && (context.ApiDescription.CustomAttributes().Any((a) => a is AuthorizeAttribute)
                        || descriptor.ControllerTypeInfo.GetCustomAttribute<AuthorizeAttribute>() != null))
                {
                    operation.Security.Add(new OpenApiSecurityRequirement
                    {
                        [new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer",
                            },
                        }] = Array.Empty<string>()
                    });
                }
            }

            if (operation.RequestBody?.Content.ContainsKey("multipart/form-data") ?? false)
            {
                foreach (var content in operation.RequestBody.Content)
                {
                    var requiredProps = content.Value.Schema.Required;
                    var props = content.Value.Schema.Properties;
                    foreach (var prop in props)
                    {
                        var paramterDescription = context.ApiDescription.ParameterDescriptions.FirstOrDefault(paramDesc => paramDesc.Name == prop.Key);
                        if (!requiredProps.Contains(prop.Key) && paramterDescription != null && paramterDescription.Type.IsReferenceOrNullableType())
                        {
                            prop.Value.Nullable = true;
                        }
                    }
                }
            }
        }
    }

}
